#include "Format.h"
#include "Markup.h"

void CFormat::load(const std::string &strXml)
{
    bool bFinished = 0;
    CMarkup xml;
    xml.Load(strXml.c_str());
    xml.ResetPos();

    if (!xml.FindElem())
        bFinished = 1;

    while (!bFinished)
    {
        // Process element
        std::string strTag = xml.GetTagName();
        if (strTag.compare("item") == 0)
        {
            CItem item;
            item.length = atoi(xml.GetAttrib("length").data());
            item.name = xml.GetAttrib("name");
            item.unit = xml.GetAttrib("unit");
            const std::string &type = xml.GetAttrib("type");
            item.type = CItem::E_Unknown;
            if (type.compare("char") == 0)
            {
                item.type = CItem::E_Char;
                item.value = '\0';
            }
            else if (type.compare("unsigned char") == 0)
            {
                item.type = CItem::E_UnsignedChar;
                item.value = (unsigned char)0;
            }
            else if (type.compare("short") == 0)
            {
                item.type = CItem::E_Short;
                item.value = (short)0;
            }
            else if (type.compare("unsigned short") == 0)
            {
                item.type = CItem::E_UnsignedShort;
                item.value = (unsigned short)0;
            }
            else if (type.compare("int") == 0)
            {
                item.type = CItem::E_Int;
                item.value = (int)0;
            }
            else if (type.compare("unsigned int") == 0)
            {
                item.type = CItem::E_UnsignedInt;
                item.value = (unsigned int)0;
            }
            else if (type.compare("long long") == 0)
            {
                item.type = CItem::E_LongLong;
                item.value = (long long)0;
            }
            else if (type.compare("unsigned long long") == 0)
            {
                item.type = CItem::E_UnsignedLongLong;
                item.value = (unsigned long long)0;
            }
            else if (type.compare("float") == 0)
            {
                item.type = CItem::E_Float;
                item.value = (float)0.0;
            }
            else if (type.compare("double") == 0)
            {
                item.type = CItem::E_Double;
                item.value = (double)0.0;
            }
            else if (type.compare("chars") == 0)
            {
                item.type = CItem::E_Chars;
                item.value = std::string("");
            }
            else if (type.compare("raw") == 0)
            {
                item.type = CItem::E_Raw;
                item.value = std::vector<unsigned char>(item.length, 0);
            }
            else if (type.compare("bit") == 0)
            {
                item.type = CItem::E_Bit;
                item.value = (unsigned long long)0;
                item.length &= 0x003F;
            }
            m_vItems.push_back(item);
        }

        // Next element (depth first)
        int bFound = xml.FindChildElem();
        while (!bFound && !bFinished)
        {
            if (xml.OutOfElem())
                bFound = xml.FindChildElem();
            else
                bFinished = 1;
        }
        if (bFound)
            xml.IntoElem();
    }
}

void CFormat::print() const
{
    printf("name------------------------value-----------------------------type--------------\n");
    for (VItem::const_iterator it = m_vItems.begin(); it != m_vItems.end(); it++)
    {
        printf("%-28s", it->name.c_str());
        switch (it->type)
        {
        case CItem::E_Char:
        {
            char c = boost::any_cast<char>(it->value);
            printf("%c(%d)%s\tchar\n", c, c, it->unit.c_str());
        }
        break;
        case CItem::E_UnsignedChar:
        {
            printf("%d%s\tunsigned char\n", boost::any_cast<unsigned char>(it->value), it->unit.c_str());
        }
        break;
        case CItem::E_Short:
        {
            printf("%d%s\tshort\n", boost::any_cast<short>(it->value), it->unit.c_str());
        }
        break;
        case CItem::E_UnsignedShort:
        {
            printf("%u%s\tunsigned short\n", boost::any_cast<unsigned short>(it->value), it->unit.c_str());
        }
        break;
        case CItem::E_Int:
        {
            printf("%d%s\tint\n", boost::any_cast<int>(it->value), it->unit.c_str());
        }
        break;
        case CItem::E_UnsignedInt:
        {
            printf("%u%s\tunsigned int\n", boost::any_cast<unsigned int>(it->value), it->unit.c_str());
        }
        break;
        case CItem::E_LongLong:
        {
            printf("%lld%s\tlong long\n", boost::any_cast<long long>(it->value), it->unit.c_str());
        }
        break;
        case CItem::E_UnsignedLongLong:
        {
            printf("%llu%s\tunsigned long long\n", boost::any_cast<unsigned long long>(it->value), it->unit.c_str());
        }
        break;
        case CItem::E_Float:
        {
            printf("%f%s\tfloat\n", boost::any_cast<float>(it->value), it->unit.c_str());
        }
        break;
        case CItem::E_Double:
        {
            printf("%lf%s\tdouble\n", boost::any_cast<double>(it->value), it->unit.c_str());
        }
        break;
        case CItem::E_Chars:
        {
            printf("%s\tstring\n", boost::any_cast<std::string>(it->value).c_str());
        }
        break;
        case CItem::E_Raw:
        {
            // 必须写成两行，否则无法获取到正确的数据，可能是没有构造std::vector<unsigned char>对象，或者是构造了临时对象又被析构了
            // const unsigned char *p = boost::any_cast<std::vector<unsigned char>>(it->value).data();
            const std::vector<unsigned char> &vc = boost::any_cast<std::vector<unsigned char>>(it->value);
            const unsigned char *p = vc.data();
            int n = std::min((size_t)it->length, vc.size());
            for (int i = 0; i < n; i++)
            {
                printf("%02X", *p++);
                if ((i & 0x07) == 0x07)
                {
                    printf(" ");
                }
            }
            printf("\traw\n");
        }
        break;
        case CItem::E_Bit:
        {
            unsigned long long p = boost::any_cast<unsigned long long>(it->value);
            if (it->length > 31)
            {
                printf("%llu\tbit\n", p & ~(~(unsigned long long)0 << it->length));
            }
            else
            {
                printf("%llu\tbit\n", p & ~(~0 << it->length));
            }
        }
        break;
        case CItem::E_Unknown:
        default:
            break;
        }
    }
}

void CFormat::encode(std::vector<unsigned char> &data) const
{
    int nBits = 0;
    data.clear();
    for (VItem::const_iterator it = m_vItems.begin(); it != m_vItems.end(); it++)
    {
        switch (it->type)
        {
        case CItem::E_Char:
        {
            char v = boost::any_cast<char>(it->value);
            data.push_back(v);
            nBits = 0;
        }
        break;
        case CItem::E_UnsignedChar:
        {
            unsigned char v = boost::any_cast<unsigned char>(it->value);
            data.push_back(v);
            nBits = 0;
        }
        break;
        case CItem::E_Short:
        {
            short v = boost::any_cast<short>(it->value);
            unsigned char *p = (unsigned char *)&v;
            data.push_back(*p++);
            data.push_back(*p);
            nBits = 0;
        }
        break;
        case CItem::E_UnsignedShort:
        {
            unsigned short v = boost::any_cast<unsigned short>(it->value);
            unsigned char *p = (unsigned char *)&v;
            data.push_back(*p++);
            data.push_back(*p);
            nBits = 0;
        }
        break;
        case CItem::E_Int:
        {
            int v = boost::any_cast<int>(it->value);
            unsigned char *p = (unsigned char *)&v;
            data.push_back(*p++);
            data.push_back(*p++);
            data.push_back(*p++);
            data.push_back(*p);
            nBits = 0;
        }
        break;
        case CItem::E_UnsignedInt:
        {
            unsigned int v = boost::any_cast<unsigned int>(it->value);
            unsigned char *p = (unsigned char *)&v;
            data.push_back(*p++);
            data.push_back(*p++);
            data.push_back(*p++);
            data.push_back(*p);
            nBits = 0;
        }
        break;
        case CItem::E_LongLong:
        {
            long long v = boost::any_cast<long long>(it->value);
            unsigned char *p = (unsigned char *)&v;
            data.push_back(*p++);
            data.push_back(*p++);
            data.push_back(*p++);
            data.push_back(*p++);
            data.push_back(*p++);
            data.push_back(*p++);
            data.push_back(*p++);
            data.push_back(*p);
            nBits = 0;
        }
        break;
        case CItem::E_UnsignedLongLong:
        {
            unsigned long long v = boost::any_cast<unsigned long long>(it->value);
            unsigned char *p = (unsigned char *)&v;
            data.push_back(*p++);
            data.push_back(*p++);
            data.push_back(*p++);
            data.push_back(*p++);
            data.push_back(*p++);
            data.push_back(*p++);
            data.push_back(*p++);
            data.push_back(*p);
            nBits = 0;
        }
        break;
        case CItem::E_Float:
        {
            float v = boost::any_cast<float>(it->value);
            unsigned char *p = (unsigned char *)&v;
            data.push_back(*p++);
            data.push_back(*p++);
            data.push_back(*p++);
            data.push_back(*p);
            nBits = 0;
        }
        break;
        case CItem::E_Double:
        {
            double v = boost::any_cast<double>(it->value);
            unsigned char *p = (unsigned char *)&v;
            data.push_back(*p++);
            data.push_back(*p++);
            data.push_back(*p++);
            data.push_back(*p++);
            data.push_back(*p++);
            data.push_back(*p++);
            data.push_back(*p++);
            data.push_back(*p);
            nBits = 0;
        }
        break;
        case CItem::E_Chars:
        {
            const std::string &v = boost::any_cast<std::string>(it->value);
            int i = std::min((unsigned short)v.size(), it->length);
            int j = it->length - i;
            data.insert(data.end(), v.data(), v.data() + i);
            if (j > 0)
            {
                data.insert(data.end(), j, 0);
            }
            nBits = 0;
        }
        break;
        case CItem::E_Raw:
        {
            const std::vector<unsigned char> &v = boost::any_cast<std::vector<unsigned char>>(it->value);
            int i = std::min((unsigned short)v.size(), it->length);
            int j = it->length - i;
            data.insert(data.end(), v.data(), v.data() + i);
            if (j > 0)
            {
                data.insert(data.end(), j, 0);
            }
            nBits = 0;
        }
        break;
        case CItem::E_Bit:
        {
            unsigned long long v = boost::any_cast<unsigned long long>(it->value);
            int o = (nBits + 7) >> 3;
            int n = (nBits + it->length + 7) >> 3;
            int c = n - o;            // 新增字节数
            int l = nBits & 0x07;     // 当前数据的最低字节需要左移的位数
            int r = (o << 3) - nBits; // 前一字节还能够装下几位
            unsigned short s = std::min((unsigned short)r, it->length);
            if (r > 0)
            {
                data.back() |= (unsigned char)((v & ~(~0 << s)) << l);
            }
            if (c > 0)
            {
                v >>= s;
                unsigned char *p = (unsigned char *)&v;
                while (c > 0)
                {
                    data.push_back(*p++);
                    c--;
                }
            }
            nBits += it->length;
        }
        break;
        case CItem::E_Unknown:
        default:
            break;
        }
    }
}

bool CFormat::decode(const std::vector<unsigned char> &data)
{
    unsigned char *p = (unsigned char *)data.data();
    return decode(p, data.size());
}

bool CFormat::decode(const unsigned char *p, int nSize)
{
    int n;
    int nBits = 0;
    for (VItem::iterator it = m_vItems.begin(); it != m_vItems.end() && nSize > 0; it++)
    {
        switch (it->type)
        {
        case CItem::E_Char:
        {
            it->value = *(char *)p++;
            nSize--;
            nBits = 0;
        }
        break;
        case CItem::E_UnsignedChar:
        {
            it->value = *p++;
            nSize--;
            nBits = 0;
        }
        break;
        case CItem::E_Short:
        {
            it->value = *(short *)p;
            p += 2;
            nSize -= 2;
            nBits = 0;
        }
        break;
        case CItem::E_UnsignedShort:
        {
            it->value = *(unsigned short *)p;
            p += 2;
            nSize -= 2;
            nBits = 0;
        }
        break;
        case CItem::E_Int:
        {
            it->value = *(int *)p;
            p += 4;
            nSize -= 4;
            nBits = 0;
        }
        break;
        case CItem::E_UnsignedInt:
        {
            it->value = *(unsigned int *)p;
            p += 4;
            nSize -= 4;
            nBits = 0;
        }
        break;
        case CItem::E_LongLong:
        {
            it->value = *(long long *)p;
            p += 8;
            nSize -= 8;
            nBits = 0;
        }
        break;
        case CItem::E_UnsignedLongLong:
        {
            it->value = *(unsigned long long *)p;
            p += 8;
            nSize -= 8;
            nBits = 0;
        }
        break;
        case CItem::E_Float:
        {
            it->value = *(float *)p;
            p += 4;
            nSize -= 4;
            nBits = 0;
        }
        break;
        case CItem::E_Double:
        {
            it->value = *(double *)p;
            p += 8;
            nSize -= 8;
            nBits = 0;
        }
        break;
        case CItem::E_Chars:
        {
            n = std::min(nSize, (int)it->length);
            unsigned char *p2 = (unsigned char *)(p + n);
            unsigned char c = *p2;
            *p2 = 0;
            it->value = std::string((const char *)p);
            *p2 = c;
            p += n;
            nSize -= n;
            nBits = 0;
        }
        break;
        case CItem::E_Raw:
        {
            n = std::min(nSize, (int)it->length);
            std::vector<unsigned char> vc;
            vc.assign(p, p + n);
            it->value = vc;
            p += n;
            nSize -= n;
            nBits = 0;
        }
        break;
        case CItem::E_Bit:
        {
            unsigned long long v = 0;
            int o = (nBits + 7) >> 3;
            int n = (nBits + it->length + 7) >> 3;
            int c = n - o;            // 新增字节数
            int l = nBits & 0x07;     // 当前数据的最低字节需要左移的位数
            int r = (o << 3) - nBits; // 前一字节还能够装下几位
            unsigned short s = std::min((unsigned short)r, it->length);
            if (r > 0)
            {
                v |= (*p >> l) & ~(~0 << s);
                if (r < it->length)
                {
                    p++;
                    nSize--;
                }
            }
            if (c > 0)
            {
                int i;
                for (i = 0; i < c - 1; i++)
                {
                    v |= ((*p++ << (8 * i)) << s);
                    nSize--;
                }
                if (c - 1 == i)
                {
                    int m = c * 8 - it->length + s; // 多分配的位数
                    if (m > 0)
                    {
                        int n = 8 - m; // 只取低n位
                        v |= (((*p & ~(~0 << n)) << (8 * i)) << s);
                    }
                    else
                    {
                        v |= ((*p << (8 * i)) << s);
                        p++;
                        nSize--;
                    }
                }
            }
            it->value = v;
            nBits += it->length;
        }
        break;
        case CItem::E_Unknown:
        default:
            break;
        }
    }
    return true;
}

boost::any g_empty;

const boost::any &CFormat::get(int index)
{
    if (index >= 0 && index < m_vItems.size())
    {
        return m_vItems[index].value;
    }
    return g_empty;
}

const boost::any &CFormat::get(const std::string &name)
{
    for (const auto &v : m_vItems)
    {
        if (v.name == name)
        {
            return v.value;
        }
    }

    return g_empty;
}

bool CFormat::set(int index, const boost::any &v)
{
    if (index >= 0 && index < m_vItems.size() && v.type() == m_vItems[index].value.type() )
    {
        m_vItems[index].value = v;
        return true;
    }
    return false;
}

bool CFormat::set(const std::string &name, const boost::any &v)
{
    for (auto &i : m_vItems)
    {
        if (i.name == name && v.type() == i.value.type() )
        {
            i.value = v;
            return true;
        }
    }
    return false;
}
